package thread;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 刘远望
 * Date: 2025-05-24
 * Time: 23:02
 */
//死锁(手写死锁代码)
public class Demo20 {
    public static void main1(String[] args) {
        Object locker1 = new Object();
        Object locker2 = new Object();

        Thread thread1 = new Thread(() -> {
            //该线程拿到第一把锁 再拿第二把锁的时候,因为第二把锁也因同样的情况不能释放，所以就会产生死锁(不能释放第一把锁)
            synchronized (locker1) {
                try {
                    Thread.sleep(1000);//加上sleep确保thread1拿到locker1
                    //不加sleep很可能thread1一口气就把locker1和locker2都拿到了 这时候t2还没动 自然无法构成死锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (locker2) {
                    System.out.println("thread1 获取到两个锁");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (locker2) {
                try {
                    Thread.sleep(1000);//加上sleep确保thread2拿到locker2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (locker1) {
                    System.out.println("thread2 获取到两个锁");
                }
            }
        });

        thread1.start();
        thread2.start();
    }

    //破除死锁的方法1

    /**
     * 请求和保持 一个线程拿到锁1之后不释放锁1的前提下获取锁2(代码中加锁的时候嵌套)
     * 解决：不要去嵌套(这种方法不通用) 有的时候嵌套无法避免
     */
    public static void main2(String[] args) {
        Object locker1 = new Object();
        Object locker2 = new Object();

        Thread thread1 = new Thread(() -> {
            //取消嵌套
            synchronized (locker1) {
                try {
                    Thread.sleep(1000);//加上sleep确保thread1拿到locker1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            synchronized (locker2) {
                System.out.println("thread1 获取到两个锁");
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (locker2) {
                try {
                    Thread.sleep(1000);//加上sleep确保thread2拿到locker2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            synchronized (locker1) {
                System.out.println("thread2 获取到两个锁");
            }
        });

        thread1.start();
        thread2.start();
    }

    //破除死锁方法2

    /**
     *循环等待 多个线程多把锁之间的等待过程构成了循环 A等待B， B等待A 或 A等待B B等待C C等待A
     * 破除方法：约定好加锁的顺序
     * 例如每个线程加锁的时候先获取序号小的锁再获取大的锁
     */
    public static void main(String[] args) {
        Object locker1 = new Object();
        Object locker2 = new Object();

        Thread thread1 = new Thread(() -> {
            //都先获取小锁
            synchronized (locker1) {
                try {
                    Thread.sleep(1000);//加上sleep确保thread1拿到locker1
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (locker2) {
                    System.out.println("thread1 获取到两个锁");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (locker1) {
                try {
                    Thread.sleep(1000);//加上sleep确保thread2拿到locker2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (locker2) {
                    System.out.println("thread2 获取到两个锁");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}
